//////////////////////////////////////////ok
#include"stdafx.h"

#include "bochs.h"


void IA32_CPU::RETnear16_Iw(Ia32_Instruction_c *i)
{
	Bit16u return_IP;
	pop_16(&return_IP);
	if (return_IP > sregs[IA32_SEG_REG_CS].cache.u.segment.limit_scaled) 
	{
		exception(IA32_GP_EXCEPTION, 0, 0);
	}

	EIP = return_IP;
	Bit16u imm16 = i->Iw();
	if ( sregs[IA32_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
		ESP += imm16;
	else
		SP  += imm16;

}

void IA32_CPU::RETnear16(Ia32_Instruction_c *i)
{
  
	Bit16u return_IP;
	pop_16(&return_IP);
	if (return_IP >  sregs[IA32_SEG_REG_CS].cache.u.segment.limit_scaled) 
	{
		exception(IA32_GP_EXCEPTION, 0, 0);
	}
	EIP = return_IP;

}

void IA32_CPU::RETfar16_Iw(Ia32_Instruction_c *i)
{
	Bit16s imm16;
	invalidate_prefetch_q();
	imm16 = i->Iw();
    return_protected(i, imm16);
	return;
}

void IA32_CPU::RETfar16(Ia32_Instruction_c *i)
{
	invalidate_prefetch_q();
    return_protected(i, 0);
	return;
}

void IA32_CPU::CALL_Aw(Ia32_Instruction_c *i)
{
	Bit32u new_EIP;
	new_EIP = EIP + (Bit32s) i->Id();
	new_EIP &= 0x0000ffff;
	if (new_EIP >  sregs[IA32_SEG_REG_CS].cache.u.segment.limit_scaled)
	{
		exception(IA32_GP_EXCEPTION, 0, 0);
	}

	push_16(IP);
	EIP = new_EIP;
}

void IA32_CPU::CALL16_Ap(Ia32_Instruction_c *i)
{
	Bit16u cs_raw;
	Bit16u disp16;
	invalidate_prefetch_q();
	disp16 = i->Iw();
	cs_raw = i->Iw2();
    call_protected(i, cs_raw, disp16);
	return;
}

void IA32_CPU::CALL_Ew(Ia32_Instruction_c *i)
{
	Bit16u op1_16;
	if (i->modC0()) 
	{
		op1_16 = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
	}

	if (op1_16 >  sregs[IA32_SEG_REG_CS].cache.u.segment.limit_scaled)
	{
		exception(IA32_GP_EXCEPTION, 0, 0);
	}

	push_16(IP);
	EIP = op1_16;

}

void IA32_CPU::CALL16_Ep(Ia32_Instruction_c *i)
{
	Bit16u cs_raw;
	Bit16u op1_16;
	invalidate_prefetch_q();
	if (i->modC0()) 
	{
		exception(IA32_UD_EXCEPTION, 0, 0);
	}

	read_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
	read_virtual_word(i->seg(), IA32_RMAddr(i)+2, &cs_raw);
	call_protected(i, cs_raw, op1_16);
	return;
}

void IA32_CPU::JMP_Jw(Ia32_Instruction_c *i)
{
	Bit32u new_EIP = EIP + (Bit32s) i->Id();
	new_EIP &= 0x0000ffff;
	branch_near32(new_EIP);
}

void IA32_CPU::JCC_Jw(Ia32_Instruction_c *i)
{
	bx_bool condition;
	switch (i->b1() & 0x0f) 
	{
		case 0x00: /* JO */ condition = get_OF(); break;
		case 0x01: /* JNO */ condition = !get_OF(); break;
		case 0x02: /* JB */ condition = get_CF(); break;
		case 0x03: /* JNB */ condition = !get_CF(); break;
		case 0x04: /* JZ */ condition = get_ZF(); break;
		case 0x05: /* JNZ */ condition = !get_ZF(); break;
		case 0x06: /* JBE */ condition = get_CF() || get_ZF(); break;
		case 0x07: /* JNBE */ condition = !get_CF() && !get_ZF(); break;
		case 0x08: /* JS */ condition = get_SF(); break;
		case 0x09: /* JNS */ condition = !get_SF(); break;
		case 0x0A: /* JP */ condition = get_PF(); break;
		case 0x0B: /* JNP */ condition = !get_PF(); break;
		case 0x0C: /* JL */ condition = getB_SF() != getB_OF(); break;
		case 0x0D: /* JNL */ condition = getB_SF() == getB_OF(); break;
		case 0x0E: /* JLE */ condition = get_ZF() || (getB_SF() != getB_OF());
			break;
		case 0x0F: /* JNLE */ condition = (getB_SF() == getB_OF()) && !get_ZF();
			break;
		default:
			condition = 0; // For compiler...all targets should set condition.
		break;
	}

	if (condition) 
	{
		Bit32u new_EIP = EIP + (Bit32s) i->Id();
		new_EIP &= 0x0000ffff;
		branch_near32(new_EIP);
	}

}

void IA32_CPU::JZ_Jw(Ia32_Instruction_c *i)
{
	if (get_ZF()) 
	{
		Bit32u new_EIP = EIP + (Bit32s) i->Id();
		new_EIP &= 0x0000ffff;
		branch_near32(new_EIP);
	}
}

void IA32_CPU::JNZ_Jw(Ia32_Instruction_c *i)
{
	if (!get_ZF()) 
	{
		Bit32u new_EIP = EIP + (Bit32s) i->Id();
		new_EIP &= 0x0000ffff;
		branch_near32(new_EIP);
	}
}

void IA32_CPU::JMP_Ew(Ia32_Instruction_c *i)
{
	Bit16u op1_16;
	if (i->modC0()) 
	{
		op1_16 = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
	}
	Bit32u new_EIP = op1_16;
	branch_near32(new_EIP);
}

  /* Far indirect jump */

void IA32_CPU::JMP16_Ep(Ia32_Instruction_c *i)
{
	Bit16u cs_raw;
	Bit16u op1_16;
	invalidate_prefetch_q();
	if (i->modC0()) 
	{
		/* far indirect must specify a memory address */
		exception(IA32_UD_EXCEPTION, 0, 0);
	}

	read_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
	read_virtual_word(i->seg(), IA32_RMAddr(i)+2, &cs_raw);
	jump_protected(i, cs_raw, op1_16);
	return;
}

void IA32_CPU::IRET16(Ia32_Instruction_c *i)
{
	invalidate_prefetch_q();
	iret_protected(i);
	return;
}
